using System.Collections;
using System.Collections.Generic;
using System;

//(c) 2011 VDZ
//made for Ludum Dare 22
//
//Licensed under Creative Commons Attribution-NonCommercial 3.0 Unported (CC BY-NC 3.0) 
//
//You are free:
//# to Share — to copy, distribute and transmit the work
//# to Remix — to adapt the work 
//
//Under the following conditions:
//# Attribution — You must attribute the work in the manner specified by the author or licensor
//      (but not in any way that suggests that they endorse you or your use of the work).
//# Noncommercial — You may not use this work for commercial purposes. 
//
//With the understanding that: 
//# Waiver — Any of the above conditions can be waived if you get permission from the copyright holder. 
//# Public Domain — Where the work or any of its elements is in the public domain under applicable law,
//      that status is in no way affected by the license. 
//# Other Rights — In no way are any of the following rights affected by the license:
//  * Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations;
//  * The author's moral rights;
//  * Rights other persons may have either in the work itself or in how the work is used, such as publicity
//      or privacy rights.

public static partial class GameMain {

    public enum EndingFlag
    {
        None,
        DepressionEnd,
        RentEnd,
        HealthEnd,
        SocietyEnd
    }

    //Game stats
    public static int day;
    public static EndingFlag endingFlag;
    public static List<Item> food;
    public static List<Item> anime;
    public static List<Item> manga;
    public static List<Item> games;

    //Stats
    public static int cash;
    public static int depression;
    public static int courage;
    public static int social;
    public static int hope;
    public static int health;

    //Other player variables
    public static int parent_income;
    public static int welfare_income;
    public static int welfare_start;
    public static int mmo_subscription_cost;
    public static bool mmo_subscription_enabled;
    public static int mmo_subscription_start;
    public static int mmo_addiction;
    public static int mmo_last_date;
    public static int mmo_debt;
    public static int rent;
    public static int debt;
    public static int missed_rent;
    public static int illness_duration;
    public static List<Item> items;

    //Other variables
    public static IGUI gui;

    public static void FullReset()
    {
        day = 0;
        endingFlag = EndingFlag.None;
        food = new List<Item>();
        anime = new List<Item>();
        manga = new List<Item>();
        games = new List<Item>();

        //Stats
        cash = 0;
        depression = 0;
        courage = 0;
        social = 0;
        hope = 0;
        health = 0;

        //Other player variables
        parent_income = 0;
        welfare_income = 0;
        welfare_start = 0;
        mmo_subscription_cost = 0;
        mmo_subscription_enabled = false;
        mmo_subscription_start = 0;
        mmo_addiction = 0;
        mmo_last_date = 0;
        mmo_debt = 0;
        rent = 0;
        debt = 0;
        missed_rent = 0;
        illness_duration = 0;
        items = new List<Item>();
    }

    //Initializes all variables
    //Returns true if succesful
    public static bool Initialize()
    {
        endingFlag = EndingFlag.None;
        items = new List<Item>();
        food = LoadFood();
        anime = LoadAnime();
        manga = LoadManga();
        games = LoadGames();
        items.Add(new Item(food[0])); //Get two instant noodles at the start of the game
        items.Add(new Item(food[0])); //Get two instant noodles at the start of the game

        day = 1;
        cash = 500;
        depression = 0;
        courage = 20;
        social = 20;
        hope = 20;
        health = 100;

        parent_income = 500;
        welfare_income = 0;
        welfare_start = 0;
        mmo_subscription_cost = 90;
        mmo_subscription_enabled = false;
        mmo_subscription_start = 0;
        mmo_addiction = 0;
        mmo_last_date = 0;
        mmo_debt = 0;
        rent = 300;
        debt = 0;
        missed_rent = 0;
        illness_duration = 0;

        return true;
    }

    //Returns false if an ending is reached
    public static bool StartDay()
    {
        if (day - mmo_last_date > 7) mmo_subscription_enabled = false;
        gui.DayFeedback(day);
        int dailydepression = DailyDepression();
        depression += dailydepression;
        gui.DepressionFeedback(dailydepression);
        if (CheckEnd()) return false;
        LoseHope();
        LoseCourage();
        LoseSocial();
        LoseAddiction(1);

        EatFood();
        if (CheckEnd()) return false;
        ParentIncome();
        WelfareIncome();
        PayRent();
        if (CheckEnd()) return false;
        Subscription();

        Random rand = new Random();

        if (rand.NextDouble() < 0.025 && day > 4) //Parent income drops
        {
            int decrease = rand.Next(75, 126);
            LoseParent(decrease);
        }

        if (rand.NextDouble() < 0.025) //Welfare income drops
        {
            int decrease = rand.Next(30, 70);
            LoseWelfare(decrease);
        }

        if ((health < 50) && (illness_duration == 0))
        {
            if (health < 25)
            {
                if (health < 10)
                {
                    if (rand.NextDouble() < 0.4)
                    {
                        illness_duration = rand.Next(1, 7);
                        gui.GetSickFeedback(illness_duration);
                    }
                }
                else
                {
                    if (rand.NextDouble() < 0.1)
                    {
                        illness_duration = rand.Next(1, 4);
                        gui.GetSickFeedback(illness_duration);
                    }
                }
            }
            else
            {
                if (rand.NextDouble() < 0.05)
                {
                    illness_duration = rand.Next(1, 3);
                    gui.GetSickFeedback(illness_duration);
                }
            }
        }

        if (illness_duration > 0)
        {
            if (health < 6)
            {
                if (rand.NextDouble() < 0.5)
                {
                    endingFlag = EndingFlag.HealthEnd; //GAME OVER
                    return false;
                }
            }
            gui.IllnessFeedback(illness_duration);
            illness_duration--;
            gui.EndTurn();
        }
        else if (rand.Next(100) < mmo_addiction)
        {
            gui.InvoluntaryMMOFeedback();
            if (!PlayMMO())
            {
                CantPlayMMO(); //At this point you're fucked
                gui.AllowAction();
            }
        }

        else gui.AllowAction();
        return true;
    }

    public static void EndDay()
    {
        day++;
        if (!StartDay()) gui.EndGame(endingFlag);
    }

    //----------------Actions---------------
    //Returns false if player doesn't have enough money for it
    public static bool BuyItem(Item item)
    {
        if (Pay(item.price))
        {
            items.Add(item);
            
            //Item becomes sold out if not food
            int index = -1;
            switch (item.type)
            {
                case Item.ItemType.Anime: index = anime.IndexOf(item); break;
                case Item.ItemType.Manga: index = manga.IndexOf(item); break;
                case Item.ItemType.Game: index = games.IndexOf(item); break;
            }
            if (index > -1) //Not sure what's going on here if not
            {
                switch (item.type)
                {
                    case Item.ItemType.Anime: anime[index].soldOut = true; break;
                    case Item.ItemType.Manga: manga[index].soldOut = true; break;
                    case Item.ItemType.Game: games[index].soldOut = true; break;
                }
            }
            return true;
        }
        return false;
    }

    public static void BrowseBoards()
    {
        gui.BoardFeedback();
        //TODO: Hints and other nonsense
        Random rand = new Random();
        int socialchange = rand.Next(3, 10);
        if (social + socialchange > 20) socialchange -= (social + socialchange - 20);
        if (socialchange > 0)
        {
            social += socialchange;
            gui.SocialFeedback(socialchange);
        }
        int hopechange = rand.Next(-2, 15);
        ChangeHope(hopechange);
        int couragechange = rand.Next(-2, 15);
        ChangeCourage(couragechange);
        gui.EndTurn();
    }

    //Returns true if the item is consumed, false if there's still item left
    public static bool Entertainment(Item item)
    {
        int index = items.IndexOf(item);
        if (item.Use())
        {
            items.Remove(items[index]);
            gui.EndTurn();
            return true;
        }
        else items[index] = item; //Make sure changes are saved
        gui.EndTurn();
        return false;
    }

    //Returns false if you were unable to play
    public static bool PlayMMO()
    {
        if (!mmo_subscription_enabled)
        {
            if (Pay(mmo_debt))
            {
                mmo_debt = 0;
                mmo_subscription_start = day;
                mmo_subscription_cost = new Random().Next(5, 15) * 10;
                mmo_subscription_enabled = true;
            }
            else
            {
                gui.MMOFailFeedback();
                return false;
            }
        }

        mmo_last_date = day;
        Random rand = new Random();
        mmo_addiction += rand.Next(4);
        gui.MMOFeedback();
        LoseDepression(rand.Next(10, 20));
        int socialchange = rand.Next(5, 12);
        if (social + socialchange > 40) socialchange -= (social + socialchange - 40);
        if (socialchange > 0)
        {
            social += socialchange;
            gui.SocialFeedback(socialchange);
        }
        gui.EndTurn();
        return true;
    }

    //Returns false if not enough courage to go outside
    public static bool GoOutside()
    {
        if (social > 95)
        {
            endingFlag = EndingFlag.SocietyEnd;
            gui.EndGame(endingFlag);
            return true;
        }
        else
        {
            if (courage < 97 - social) return false;
            gui.OutsideFeedback();
            social += 10;
            gui.SocialFeedback(10);
            ChangeCourage(Convert.ToInt32(Math.Round(-90 + (Math.Pow((double)social, 0.5)) * 8)));
            ChangeHope(Convert.ToInt32(Math.Round(-35 + (Math.Pow((double)social, 0.5)) * 4)));
            int newdepression = Convert.ToInt32(Math.Round((float)depression * (float)(1.5 - (float)(0.5f * (float)((float)social / 100f)))));
            int change = newdepression - depression;
            depression = newdepression;
            gui.DepressionFeedback(change);
            gui.OutsideFinishFeedback();
            gui.EndTurn();
            return true;
        }
    }

    //Returns how much money was earned
    public static int WorkOnline()
    {
        gui.WorkFeedback();
        Random rand = new Random();
        if (rand.NextDouble() < 0.25) //1 in 4 chance of not finding any work
        {
            gui.WorkFinishFeedback(0);
            depression += 10; //It's that depressing
            gui.DepressionFeedback(10);
            ChangeHope(-15);
            gui.EndTurn();
            return 0;
        }

        int moneyearned = rand.Next(1, 150);
        gui.WorkFinishFeedback(moneyearned);
        int change = Convert.ToInt32(Math.Round(5f * (150 - moneyearned) / 150));
        depression += change;
        gui.DepressionFeedback(change);
        ChangeHope(Convert.ToInt32(Math.Round(10f * (150 - moneyearned) / 150)));
        cash += moneyearned;
        gui.CashFeedback(moneyearned);
        gui.EndTurn();
        return moneyearned;
    }

    //Returns the increase of welfare money
    public static int ApplyForWelfare()
    {
        if (courage < 25)
        {
            gui.WelfareFailFeedback();
            gui.EndTurn();
            return 0;
        }

        int cutwelfare = welfare_income;
        if (cutwelfare > 500) cutwelfare = 500;

        gui.WelfareApplyFeedback();
        Random rand = new Random();
        if(rand.NextDouble() < (0.6f - (0.25f * (float)((float)(100f - (float)depression) / 100f)))
            - (0.25f * ((500 - cutwelfare) / 500)))
        {
            if (welfare_income == 0) welfare_start = day;
            int change = new Random().Next(30, 100);
            welfare_income += change;
            gui.WelfareChangeFeedback(change);
            gui.EndTurn();
            return change;
        }
        else
        {
            gui.WelfareChangeFeedback(0);
            gui.EndTurn();
            return 0;
        }
    }

    //----------------Events-----------------

    //Returns the new depression value after daily depression is added
    public static int DailyDepression()
    {
        //My apologies for excessive float-casting, I've grown paranoid of C#'s automatic rounding
        float worsendepression;
        //Depression added depending on hope
        worsendepression = 0.10f * (float)(100 - hope);
        //Depression multiplied depending on days since game start
        worsendepression = (float)worsendepression * (float)(1f + (float)((float)day / (float)100));
        //Depression added depending on health
        worsendepression += (float)(100 - health) / 14f;

        return Convert.ToInt32(Math.Round(worsendepression));
    }

    //Eat a random food from your collection
    public static void EatFood()
    {
        Item food = Item.GetRandomFood(items);
        int index = items.IndexOf(food);
        if (index == -1)
        {
            gui.FoodFailedFeedback();
            ChangeHealth(-20);
        }
        else
        {
            Item item = items[index];
            gui.FoodFeedback(item);
            if (item.Use())
            {
                items.Remove(items[index]);
            }
            gui.FoodFinishFeedback();
        }
    }

    //Lose daily courage
    public static void LoseCourage()
    {
        ChangeCourage(-3);
    }

    //Lose daily hope
    public static void LoseHope()
    {
        ChangeHope(-3);
    }

    //Lose daily social contact
    public static void LoseSocial()
    {
        LoseSocial(1);
    }

    //Gain weekly parent income. Returns false if no income is gotten
    public static bool ParentIncome()
    {
        if (CheckWeekly(0))
        {
            cash += parent_income;
            gui.ParentFeedback(parent_income);
            if (parent_income > 0) return true;
        }
        return false;
    }

    //Gain weekly welfare income. Returns false if no income is gotten
    public static bool WelfareIncome()
    {
        if (CheckWeekly(welfare_start))
        {
            cash += welfare_income;
            gui.WelfareFeedback(welfare_income);
            if (welfare_income > 0) return true;
        }
        return false;
    }

    //Pay weekly MMO subscription. Returns false if there is no subscription
    public static bool Subscription()
    {
        if (CheckWeekly(mmo_subscription_start))
        {
            if (mmo_subscription_enabled)
            {
                if (Pay(mmo_subscription_cost))
                {
                    gui.MMOSubscriptionFeedback(mmo_subscription_cost);
                    return true;
                }
                else
                {
                    CancelSubscription(); //Ouch.
                    return true;
                }
            }
        }
        return false;
    }

    //Pays weekly rent. Returns false if rent is not paid
    public static bool PayRent()
    {
        if (CheckWeekly(0))
        {
            if (Pay(rent + debt))
            {
                gui.RentFeedback(rent + debt);
                return true;
            }
            else
            {
                debt += rent;
                missed_rent++;
                return false;
            }
        }
        return true;
    }

    //Cancels the player's MMO subscription
    public static void CancelSubscription()
    {
        mmo_debt += mmo_subscription_cost;
        mmo_subscription_enabled = false;
        CantPlayMMO();
    }

    public static void CantPlayMMO()
    {
        gui.MMOCantFeedback();
        int change = Convert.ToInt32(Math.Round(depression * 0.4));
        depression += change;
        gui.DepressionFeedback(change);
    }

    //--------------Other methods------------

    //Returns true if an ending has been reached, otherwise returns false
    public static bool CheckEnd()
    {
        if (depression > 99) endingFlag = EndingFlag.DepressionEnd;
        if (missed_rent == 6) endingFlag = EndingFlag.RentEnd;
        if (endingFlag != EndingFlag.None) return true;
        return false;
    }

    //Returns true if a weekly event started on the given day occurs today
    public static bool CheckWeekly(int startDay)
    {
        int mod = startDay % 7;
        if ((day % 7) == mod) return true;
        return false;
    }

    //Returns false the amount can't be paid; otherwise deducts the cash and returns true
    public static bool Pay(int amount)
    {
        if (cash < amount) return false;
        cash -= amount;
        return true;
    }

    /*public static List<Item> LoadAnime()
    {
        List<Item> items = new List<Item>();
        items.Add(new Item("Welcome to the JHA!", "Classic black humor/drama anime series about a hikikomori reintegrating into society.",
            Item.ItemType.Anime, 0, -10, 30, 30, 100));
        items.Add(new Item("Fate/Minus One", "Prequel to the popular Fate/Leave Day game and anime series.",
            Item.ItemType.Anime, 0, -20, 20, 0, 90));
        return items;
    }*/

    /*public static List<Item> LoadManga()
    {
        List<Item> items = new List<Item>();
        items.Add(new Item("Welcome to the JHA!", "Classic black humor/drama manga series about a hikikomori reintegrating into society.",
            Item.ItemType.Manga, 0, -10, 30, 30, 100));
        items.Add(new Item("Life Note", "A thrilling story about a student who becomes capable of deciding who lives and who dies.",
            Item.ItemType.Anime, 0, 5, 40, -5, 40));
        return items;
    }*/

    /*public static List<Item> LoadGames()
    {
        List<Item> items = new List<Item>();
        items.Add(new Item("Super Smash Sisters", "Fighting game where characters from various Nindento series fight against each other.",
            Item.ItemType.Game, 0, -20, 0, 0, 500, 30));
        items.Add(new Item("Ghostic II", "After defeating a demon and breaking the barrier, our hero finds himself slaying dragons!",
            Item.ItemType.Game, 0, -20, 5, 0, 150, 8));
        items.Add(new Item("Depression bomb", "", Item.ItemType.Game, 0, 200, 0, 0, 1));
        items.Add(new Item("Health bomb", "", Item.ItemType.Game, -200, 0, 0, 0, 1));
        items.Add(new Item("Test Object", "test description", Item.ItemType.Game, 2, 3, 4, 5, 1, 6, 7));
        items.Add(new Item("Teferi's Puzzle Box", "maakt vrienden", Item.ItemType.Game, -5, 20, -10, 40, 4, 1, 4));
        return items;
    }*/

    //-----------0-100 cap functions--------

    //Gain or lose the specified amount of courage. Returns the amount modified
    public static int ChangeCourage(int amount)
    {
        int change = amount;
        courage += amount;
        if (courage > 100) { change -= (courage - 100); courage = 100; }
        if (courage < 0) { change += courage; courage = 0; }
        gui.CourageFeedback(change);
        return change;
    }

    //Gain or lose the specified amount of health. Returns the amount modified
    public static int ChangeHealth(int amount)
    {
        int change = amount;
        health += amount;
        if (health > 100) { change -= (health - 100); health = 100; }
        if (health < 0) { change += health; health = 0; }
        gui.HealthFeedback(change);
        return change;
    }

    //Gain or lose the specified amount of hope. Returns the amount modified
    public static int ChangeHope(int amount)
    {
        int change = amount;
        hope += amount;
        if (hope > 100) { change -= (hope - 100); hope = 100; }
        if (hope < 0) { change += hope; hope = 0; }
        gui.HopeFeedback(change);
        return change;
    }

    //------------0-cap functions-----------

    //Decreases MMO addiction by the specified amount. Returns the amount modified
    public static int LoseAddiction(int amount)
    {
        int change = amount;
        mmo_addiction -= amount;
        if (mmo_addiction < 0) { change += mmo_addiction; mmo_addiction = 0; }
        return change;
    }

    //Lose the specified amount of depression. Returns the amount modified
    public static int LoseDepression(int amount)
    {
        int change = amount;
        depression -= amount;
        if (depression < 0) { change += depression; depression = 0; }
        gui.DepressionFeedback(-change);
        return change;
    }

    //Decreases parent income by the specified amount. Returns the amount modified
    public static int LoseParent(int amount)
    {
        int change = amount;
        parent_income -= amount;
        if (parent_income < 0) { change += parent_income; parent_income = 0; }
        gui.ParentDropFeedback(-change);
        return change;
    }

    //Lose the specified amount of social contact. Returns the amount modified
    public static int LoseSocial(int amount)
    {
        int change = amount;
        social -= amount;
        if (social < 0) { change += social; social = 0; }
        gui.SocialFeedback(-change);
        return change;
    }

    //Decreases welfare income by the specified amount. Returns the amount modified
    public static int LoseWelfare(int amount)
    {
        int change = amount;
        welfare_income -= amount;
        if (welfare_income < 0) { change += welfare_income; welfare_income = 0; }
        if (change != 0)
        {
            gui.WelfareChangeFeedback(-change);
        }
        return change;
    }
}
